package com.yum.ms.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yum.ms.entity.Order;
import com.yum.ms.entity.SeckillGoods;
import com.yum.ms.entity.SeckillOrder;
import com.yum.ms.entity.User;
import com.yum.ms.entity.vo.GoodsVO;
import com.yum.ms.mapper.OrderMapper;
import com.yum.ms.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Yum
 * @since 2022-02-16
 */
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Autowired
    private ISeckillGoodsService seckillGoodsService;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private ISeckillOrderService seckillOrderService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IGoodsService goodsService;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 秒杀
     * @param user
     * @param goodsVO
     * @return
     */
    @Transactional
    @Override
    public Order seckill(User user, GoodsVO goodsVO) {
        ValueOperations valueOperations = redisTemplate.opsForValue();
        // 用户信息
        User u = userService.getOne(new QueryWrapper<User>().eq("id",user.getId()));
        // 秒杀商品减库存
        SeckillGoods seckillGoods = seckillGoodsService.getOne(new QueryWrapper<SeckillGoods>()
                .eq("goods_id",goodsVO.getId())
        );
        seckillGoods.setStockCount(seckillGoods.getStockCount()-1);
        seckillGoodsService.update(new UpdateWrapper<SeckillGoods>().setSql("stock_count = "+
                "stock_count-1").eq("goods_id",goodsVO.getId()).gt("stock_count",0));
        if(seckillGoods.getStockCount() < 0) {
            // 当商品数量为0时 1-1 = 0,算又购买了一次得加入订单
            valueOperations.set("isStockEmpty:"+goodsVO.getId(),"0");
            return null;
        }
        // 生成订单
        Order order = new Order();
        order.setUserId(user.getId());
        order.setGoodsId(goodsVO.getId());
        order.setDeliveryAddrId(0L);
        order.setGoodsName(goodsVO.getGoodsName());
        order.setGoodsCount(1);
        order.setGoodsPrice(seckillGoods.getSeckillPrice());
        order.setOrderChannel(1);
        order.setStatus(0);
        order.setCreateTime(LocalDateTime.now());
        order.setPayTime(LocalDateTime.now());
        orderMapper.insert(order);
        // 生成秒杀订单
        SeckillOrder seckillOrder = new SeckillOrder();
        seckillOrder.setUserId(user.getId());
        seckillOrder.setOrderId(order.getId());
        seckillOrder.setGoodsId(goodsVO.getId());
        seckillOrderService.save(seckillOrder);
        // redis
        redisTemplate.opsForValue().set("order:" + user.getId() +":"+ goodsVO.getId(),
                seckillOrder);
        Map<String,Object> info = goodsService.info(goodsVO);
        log.info("用户:{},秒杀商品:{},订单号:{},秒杀时间:{},库存:{},开始时间:{},秒杀状态:{},秒杀倒计时:{}秒",
                u.getName(),order.getGoodsName(),seckillOrder.getOrderId(),
                order.getPayTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                seckillGoods.getStockCount(),
                info.get("startDate"),info.get("status"),info.get("remainSeconds")
        );
        return order;
    }

    /**
     * 获取秒杀地址
     * @param userId
     * @param goodsId
     * @return
     */
    @Override
    public String createPath(Long userId, Long goodsId) {

        String str = MD5.create().digestHex16(UUID.fastUUID().toString() + "123456");
        redisTemplate.opsForValue().set("seckillPath:"+ userId + ":" + goodsId,
                str,60, TimeUnit.SECONDS);
        return str;
    }

    /**
     * 校验秒杀地址
     * @param path
     * @param user
     * @param goodsId
     * @return
     */
    @Override
    public boolean checkPath(String path, User user, Long goodsId) {
        if(user == null || goodsId < 0 || StringUtils.isEmpty(path)) {
            return false;
        }
        String redisPath = (String) redisTemplate.opsForValue().get("seckillPath:"+ user.getId() + ":" + goodsId);
        return path.equals(redisPath);
    }
}
